1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.math.matrix; 12 import core.math; 13 14 enum MatrixType 15 { 16 COLUMN_MAJOR, 17 ROW_MAJOR 18 } 19 20 struct Matrix3 21 { 22 float[9] values; 23 pragma(inline) inout ref auto opIndex(size_t i) return 24 { 25 return values[i]; 26 } 27 pragma(inline) inout ref auto opIndex(size_t i, size_t j) return 28 { 29 return values[i*3+j]; 30 } 31 pragma(inline, true) 32 static Matrix3 translation(float x, float y) 33 { 34 return Matrix3([ 35 1, 0, 0, 36 0, 1, 0, 37 x, y, 1 38 ]); 39 } 40 static Matrix3 identity() 41 { 42 return Matrix3([ 43 1,0,0, 44 0,1,0, 45 0,0,1 46 ]); 47 } 48 Matrix3 translate(float x, float y) 49 { 50 return this * translation(x,y); 51 } 52 53 Matrix3 scale(float x, float y) 54 { 55 return this * Matrix3([ 56 x, 0, 0, 57 0, y, 0, 58 0, 0, 1 59 ]); 60 } 61 Matrix3 transpose() 62 { 63 return Matrix3([ 64 this[0], this[3], this[6], 65 this[1], this[4], this[7], 66 this[2], this[5], this[8] 67 ]); 68 } 69 70 static Matrix3 rotation(float radians) 71 { 72 float c = cos(radians); 73 float s = sin(radians); 74 75 return Matrix3([ 76 c, s, 0, 77 -s, c, 0, 78 0, 0, 1 79 ]); 80 } 81 82 Matrix3 rotate(float radians) 83 { 84 return this * rotation(radians); 85 } 86 87 88 Matrix3 opBinary(string op, R)(const R rhs) const 89 { 90 Matrix3 ret; 91 ret.values = this.values; 92 static if(op == "*") 93 { 94 static if(is(R == float)) 95 { 96 ret[]*= rhs; 97 } 98 else //Matrix case 99 { 100 for(uint i = 0; i < 9; i+=3) 101 { 102 ret[i] = values[i]*rhs[0] +values[i+1]*rhs[3] + values[i+2]*rhs[6]; 103 ret[i+1] = values[i]*rhs[1] +values[i+1]*rhs[4] + values[i+2]*rhs[7]; 104 ret[i+2] = values[i]*rhs[2] +values[i+1]*rhs[5] + values[i+2]*rhs[8]; 105 } 106 } 107 } 108 else static if(op == "+") 109 { 110 foreach(i, v; values) 111 ret[i]+=rhs[i]; 112 } 113 else static if(op == "-") 114 { 115 foreach(i, v; values) 116 ret[i]-=rhs[i]; 117 } 118 else static if(op == "/") 119 { 120 static if(is(R == float)) 121 { 122 ret[]/=rhs; 123 } 124 } 125 return ret; 126 } 127 128 T opCast(T)() const 129 { 130 static assert(is(T == float[9]), "Matrix3 can only be cast to float[9]"); 131 return values; 132 } 133 134 alias values this; 135 } 136 137 struct Matrix4 138 { 139 float[16] values; 140 141 static Matrix4 identity() 142 { 143 return Matrix4([ 144 1.0, 0, 0, 0, 145 0, 1.0, 0, 0, 146 0, 0, 1.0, 0, 147 0, 0, 0, 1.0 148 ]); 149 } 150 pragma(inline) inout ref auto opIndex(size_t i) return 151 { 152 return values[i]; 153 } 154 pragma(inline) inout ref auto opIndex(size_t i, size_t j) return 155 { 156 return values[i*4+j]; 157 } 158 pragma(inline, true) 159 static Matrix4 translation(float x, float y, float z) 160 { 161 return Matrix4([ 162 1, 0, 0, 0, 163 0, 1, 0, 0, 164 0, 0, 1, 0, 165 x, y, z, 1 166 ]); 167 } 168 Matrix4 translate(float x, float y, float z) 169 { 170 return this * translation(x,y,z); 171 } 172 173 static Matrix4 createScale(float x, float y, float z) 174 { 175 return Matrix4([ 176 x, 0, 0, 0, 177 0, y, 0, 0, 178 0, 0, z, 0, 179 0, 0, 0, 1 180 ]); 181 } 182 183 Matrix4 scale(float x, float y, float z) 184 { 185 return this * Matrix4([ 186 x, 0, 0, 0, 187 0, y, 0, 0, 188 0, 0, z, 0, 189 0, 0, 0, 1 190 ]); 191 } 192 Matrix4 transpose() 193 { 194 return Matrix4([ 195 this[0], this[4], this[8], this[12], 196 this[1], this[5], this[9], this[13], 197 this[2], this[6], this[10], this[14], 198 this[3], this[7], this[11], this[15] 199 ]); 200 } 201 202 static Matrix4 rotationX(float radians) 203 { 204 float c = cos(radians); 205 float s = sin(radians); 206 207 return Matrix4([ 208 1, 0, 0, 0, 209 0, c, s, 0, 210 0,-s, c, 0, 211 0, 0, 0, 1 212 ]); 213 } 214 215 static Matrix4 rotationY(float radians) 216 { 217 float c = cos(radians); 218 float s = sin(radians); 219 220 return Matrix4([ 221 c, 0, s, 0, 222 0, 1, 0, 0, 223 -s, 0, c, 0, 224 0, 0, 0, 1 225 ]); 226 } 227 static Matrix4 rotationZ(float radians) 228 { 229 float c = cos(radians); 230 float s = sin(radians); 231 232 return Matrix4([ 233 c, s, 0, 0, 234 -s, c, 0, 0, 235 0, 0, 1, 0, 236 0, 0, 0, 1 237 ]); 238 } 239 240 Matrix4 rotate(float x_angle, float y_angle, float z_angle) 241 { 242 return this * rotationX(x_angle) * rotationY(y_angle) * rotationZ(z_angle); 243 } 244 245 246 Matrix4 opBinary(string op, R)(const R rhs) const 247 { 248 Matrix4 ret; 249 ret.values = this.values; 250 static if(op == "*") 251 { 252 static if(is(R == float)) 253 { 254 ret[]*= rhs; 255 } 256 else //Matrix case 257 { 258 for(uint i = 0; i < 16; i+=4) 259 { 260 ret[i] = values[i]*rhs[0] +values[i+1]*rhs[4] + values[i+2]*rhs[8] + values[i+3]*rhs[12]; 261 ret[i+1] = values[i]*rhs[1] +values[i+1]*rhs[5] + values[i+2]*rhs[9] + values[i+3]*rhs[13]; 262 ret[i+2] = values[i]*rhs[2] +values[i+1]*rhs[6] + values[i+2]*rhs[10] + values[i+3]*rhs[14]; 263 ret[i+3] = values[i]*rhs[3] +values[i+1]*rhs[7] + values[i+2]*rhs[11] + values[i+3]*rhs[15]; 264 } 265 } 266 } 267 else static if(op == "+") 268 { 269 foreach(i, v; values) 270 ret[i]+=rhs[i]; 271 } 272 else static if(op == "-") 273 { 274 foreach(i, v; values) 275 ret[i]-=rhs[i]; 276 } 277 else static if(op == "/") 278 { 279 static assert(is(R == float), "Only float is valid for matrix division"); 280 ret[]/=rhs; 281 } 282 return ret; 283 } 284 285 /** 286 * Based on the document on MSDN: 287 * https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixorthooffcenterlh?redirectedfrom=MSDN 288 */ 289 static Matrix4 orthoLH(float left, float right, float bottom, float top, float znear, float zfar) 290 { 291 292 return Matrix4([ 293 2/(right-left), 0, 0, 0, 294 0, 2/(top-bottom), 0, 0, 295 0, 0, 1/(zfar-znear), 0, 296 (left+right)/(left-right), (top+bottom)/(bottom-top), -znear/(znear-zfar), 1 297 ]); 298 } 299 300 static Matrix4 alternateHandedness(Matrix4 mat) 301 { 302 return Matrix4([ 303 1, 0, 0, 0, 304 0, 1, 0, 1, 305 0, 0,-1, 0, 306 0, 0, 0, 1 307 ]) * mat; 308 } 309 310 alias values this; 311 } 312 313 auto toString()(in Matrix3 mat) @nogc 314 { 315 import hip.util.conv; 316 import hip.util.string; 317 String ret = '['; 318 for(uint i = 0; i < 9; i++) 319 { 320 if(i != 0) 321 { 322 if(i%3 == 0) 323 ret~= "]\n["; 324 else 325 ret~=", "; 326 } 327 toStringRange(ret, mat[i]); 328 } 329 ret~= ']'; 330 return ret; 331 } 332 333 auto toString()(in Matrix4 mat) @nogc 334 { 335 import hip.util.conv; 336 import hip.util.string; 337 String ret = "["; 338 339 for(uint i = 0; i < 16; i++) 340 { 341 if(i != 0) 342 { 343 if(i%4 == 0) 344 ret~= "]\n["; 345 else 346 ret~=", "; 347 } 348 toStringRange(ret, mat[i]); 349 } 350 ret~= ']'; 351 return ret; 352 }